home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / elvis172.zip / ref.c < prev    next >
C/C++ Source or Header  |  1993-03-28  |  13KB  |  551 lines

  1. /* ref2.c */
  2.  
  3. /* This is a totally rewritten version of ref.  This version looks for the
  4.  * desired function name in the "tags" file, and then reads the header out
  5.  * from the source file.  There is no longer any need for a "refs" file.
  6.  *
  7.  * Usage:    ref [-t] [-f file] [-c class] tag
  8.  * Options:    -t       output tag info, not the description
  9.  *        -f file       default filename for static functions
  10.  *        -c class   default class names for class functions
  11.  */
  12. #ifdef __STDC__
  13. # include <string.h>
  14. # include <stdlib.h>
  15. #endif
  16.  
  17. #include <stdio.h>
  18. #include "config.h"
  19.  
  20. extern char    *cktagdir P_((char *, char *));
  21. extern int    getline P_((char *, int, FILE *));
  22. extern int    lookup P_((char *, char *));
  23. extern int    find P_((char *));
  24. extern void    usage P_((void));
  25. extern int    countcolons P_((char *));
  26. extern void    main P_((int, char **));
  27.  
  28.  
  29. /* This is the default path that is searched for tags */
  30. #if OSK
  31. # define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib"
  32. #else
  33. # if ANY_UNIX
  34. #  define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib"
  35. # else
  36. #  if MSDOS || TOS || OS2
  37. #   define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib"
  38. #   define SEP ';'
  39. #  else
  40. #   if AMIGA
  41. #    define DEFTAGPATH ".;Include:;Include:sys"
  42. #    define SEP ';'
  43. #   else /* any other OS */
  44. #    define DEFTAGPATH "."
  45. #   endif
  46. #  endif
  47. # endif
  48. #endif
  49.  
  50. #ifndef SEP
  51. # define SEP ':'
  52. #endif
  53.  
  54.  
  55. /* These variables reflect the command-line options given by the user. */
  56. int    taginfo;    /* boolean: give only the tag info? (not header?) */
  57. char    *def_file;    /* default filename for static functions */
  58. char    *def_class;    /* default classname for class members */
  59. int    colons;        /* #colons in tag: 0=normal, 1=static, 2=member */
  60.  
  61. /* This function checks for a tag in the "tags" file of given directory.
  62.  * If the tag is found, then it returns a pointer to a static buffer which
  63.  * contains the filename, a tab character, and a linespec for finding the
  64.  * the tag.  If the tag is not found in the "tags" file, or if the "tags"
  65.  * file cannot be opened or doesn't exist, then this function returns NULL.
  66.  */
  67. char *cktagdir(tag, dir)
  68.     char    *tag;    /* name of the tag to look for */
  69.     char    *dir;    /* name of the directory to check */
  70. {
  71.     char    buf[BLKSIZE];
  72.     static char found[BLKSIZE];
  73.     FILE    *tfile;
  74.     int    len;
  75.  
  76. #if AMIGA
  77.     if (dir[strlen(dir) - 1] == COLON)
  78.         sprintf(buf, "%s%s", dir, TAGS);   /* no slash after colon. */
  79.     else
  80. #endif
  81.     /* construct the name of the "tags" file in this directory */
  82.     sprintf(buf, "%s%c%s", dir, SLASH, TAGS);
  83.  
  84.     /* Try to open the tags file.  Return NULL if can't open */
  85. #if AMIGA
  86.     if (buf[0] == '.' && buf[1] == SLASH)
  87.         tfile = fopen(&buf[2], "r");
  88.     else
  89. #endif
  90.     tfile = fopen(buf, "r");
  91.     if (!tfile)
  92.     {
  93.         return (char *)0;
  94.     }
  95.  
  96.     /* compute the length of the tagname once */
  97.     len = strlen(tag);
  98.  
  99.     /* read lines until we get the one for this tag */
  100.     found[0] = '\0';
  101.     while (fgets(buf, sizeof buf, tfile))
  102.     {
  103.         /* is this the one we want? */
  104.         if (!strncmp(buf, tag, len) && buf[len] == '\t')
  105.         {
  106.             /* we've found a match -- remember it */
  107.             strcpy(found, buf);
  108.  
  109.             /* if there is no default file, or this match is in
  110.              * the default file, then we've definitely found the
  111.              * one we want.  Break out of the loop now.
  112.              */
  113.             if (!def_file || !strncmp(&buf[len + 1], def_file, strlen(def_file)))
  114.             {
  115.                 break;
  116.             }
  117.         }
  118.     }
  119.  
  120.     /* we're through reading */
  121.     fclose(tfile);
  122.  
  123.     /* if there's anything in found[], use it */
  124.     if (found[0])
  125.     {
  126.         return &found[len + 1];
  127.     }
  128.  
  129.     /* else we didn't find it */
  130.     return (char *)0;
  131. }
  132.  
  133. /* This function reads a single textline from a binary file.  It returns
  134.  * the number of bytes read, or 0 at EOF.
  135.  */
  136. int getline(buf, limit, fp)
  137.     char    *buf;    /* buffer to read into */
  138.     int    limit;    /* maximum characters to read */
  139.     FILE    *fp;    /* binary stream to read from */
  140. {
  141.     int    bytes;    /* number of bytes read so far */
  142.     int    ch;    /* single character from file */
  143.  
  144.     for (bytes = 0, ch = 0; ch != '\n' && --limit > 0 && (ch = getc(fp)) != EOF; bytes++)
  145.     {
  146. #if MSDOS || TOS || OS2
  147.         /* since this is a binary file, we'll need to manually strip CR's */
  148.         if (ch == '\r')
  149.         {
  150.             continue;
  151.         }
  152. #endif
  153.         *buf++ = ch;
  154.     }
  155.     *buf = '\0';
  156.  
  157.     return bytes;
  158. }
  159.  
  160.  
  161. /* This function reads a source file, looking for a given tag.  If it finds
  162.  * the tag, then it displays it and returns TRUE.  Otherwise it returns FALSE.
  163.  * To display the tag, it attempts to output any introductory comment, the
  164.  * tag line itself, and any arguments.  Arguments are assumed to immediately
  165.  * follow the tag line, and start with whitespace.  Comments are assumed to
  166.  * start with lines that begin with "/*", "//", "(*", or "--", and end at the
  167.  * tag line or at a blank line.
  168.  */
  169. int lookup(dir, entry)
  170.     char    *dir;    /* name of the directory that contains the source */
  171.     char    *entry;    /* source filename, <Tab>, linespec */
  172. {
  173.     char    *name;        /* basename of source file */
  174.     char    buf[BLKSIZE];    /* pathname of source file */
  175.     long    lnum;        /* desired line number */
  176.     long    thislnum;    /* current line number */
  177.     long    here;        /* seek position where current line began */
  178.     long    comment;    /* seek position of introductory comment, or -1L */
  179.     FILE    *sfile;        /* used for reading the source file */
  180.     int    len;        /* length of string */
  181.     int    noargs = 0;    /* boolean: don't show lines after tag line? */
  182.     char    *ptr;
  183.  
  184.  
  185.     /* construct the pathname of the source file */
  186.     name = entry;
  187.     strcpy(buf, dir);
  188.     ptr = buf + strlen(buf);
  189. #if AMIGA
  190.     if (ptr[-1] != COLON)
  191. #endif
  192.     *ptr++ = SLASH;
  193.     while (*entry != '\t')
  194.     {
  195.         *ptr++ = *entry++;
  196.     }
  197.     *entry++ = *ptr = '\0';
  198.  
  199.     /* searching for string or number? */
  200.     if (*entry >= '0' && *entry <= '9')
  201.     {
  202.         /* given a specific line number */
  203.         lnum = atol(entry);
  204.         entry = (char *)0;
  205.         noargs = 1;
  206.     }
  207.     else
  208.     {
  209.         /* given a string -- strip off "/^" and "$/\n" */
  210.         entry += 2;
  211.         len = strlen(entry) - 2;
  212.         if (entry[len - 1] == '$')
  213.         {
  214.             entry[len - 1] = '\n';
  215.         }
  216.         if (!strchr(entry, '('))
  217.         {
  218.             noargs = 1;
  219.         }
  220.         lnum = 0L;
  221.     }
  222.  
  223.     /* Open the file.  Note that we open the file in binary mode even
  224.      * though we know it is a text file, because ftell() and fseek()
  225.      * don't work on text files.
  226.      */
  227. #if MSDOS || TOS || OS2
  228.     sfile = fopen(buf, "rb");
  229. #else
  230. # if AMIGA
  231.     if (buf[0] == '.' && buf[1] == SLASH)
  232.         sfile = fopen(&buf[2], "r");
  233.     else
  234. # endif
  235.     sfile = fopen(buf, "r");
  236. #endif
  237.     if (!sfile)
  238.     {
  239.         /* can't open the real source file.  Try "refs" instead */
  240. #if AMIGA
  241.         if (dir[strlen(dir) - 1] == COLON)
  242.             sprintf(buf, "%srefs", dir);
  243.         else
  244. #endif
  245.         sprintf(buf, "%s%crefs", dir, SLASH);
  246. #if MSDOS || TOS || OS2
  247.         sfile = fopen(buf, "rb");
  248. #else
  249. # if AMIGA
  250.         if (buf[0] == '.' && buf[1] == SLASH)
  251.             sfile = fopen(&buf[2], "r");
  252.         else
  253. # endif
  254.         sfile = fopen(buf, "r");
  255. #endif
  256.         if (!sfile)
  257.         {
  258.             /* failed! */
  259.             return 0;
  260.         }
  261.         name = "refs";
  262.     }
  263.  
  264.     /* search the file */
  265.     for (comment = -1L, thislnum = 0; here = ftell(sfile), thislnum++, getline(buf, BLKSIZE, sfile) > 0; )
  266.     {
  267.         /* Is this the start/end of a comment? */
  268.         if (comment == -1L)
  269.         {
  270.             /* starting a comment? */
  271.             if (buf[0] == '/' && buf[1] == '*'
  272.              || buf[0] == '/' && buf[1] == '/'
  273.              || buf[0] == '(' && buf[1] == '*'
  274.              || buf[0] == '-' && buf[1] == '-')
  275.             {
  276.                 comment = here;
  277.             }
  278.         }
  279.         else
  280.         {
  281.             /* ending a comment? */
  282.             if (buf[0] == '\n' || buf[0] == '#')
  283.             {
  284.                 comment = -1L;
  285.             }
  286.         }
  287.  
  288.         /* is this the tag line? */
  289.         if (lnum == thislnum || (entry && !strncmp(buf, entry, len)))
  290.         {
  291.             /* display the filename & line number where found */
  292.             if (strcmp(dir, "."))
  293.                 printf("%s%c%s, line %ld:\n", dir, SLASH, name, thislnum);
  294.             else
  295.                 printf("%s, line %ld:\n", name, thislnum);
  296.  
  297.             /* if there were introductory comments, show them */
  298.             if (comment != -1L)
  299.             {
  300.                 fseek(sfile, comment, 0);
  301.                 while (comment != here)
  302.                 {
  303.                     getline(buf, BLKSIZE, sfile);
  304.                     fputs(buf, stdout);
  305.                     comment = ftell(sfile);
  306.                 }
  307.  
  308.                 /* re-fetch the tag line */
  309.                 fgets(buf, BLKSIZE, sfile);
  310.             }
  311.  
  312.             /* show the tag line */
  313.             fputs(buf, stdout);
  314.  
  315.             /* are we expected to show argument lines? */
  316.             if (!noargs)
  317.             {
  318.                 /* show any argument lines */
  319.                 while (getline(buf, BLKSIZE, sfile) > 0
  320.                     && buf[0] != '#'
  321.                     && strchr(buf, '{') == (char *)0)
  322.                 {
  323.                     fputs(buf, stdout);
  324.                 }
  325.             }
  326.  
  327.             /* Done!  Close the file, and return TRUE */
  328.             fclose(sfile);
  329.             return 1;
  330.         }
  331.     }
  332.  
  333.     /* not found -- return FALSE */
  334.     return 0;
  335. }
  336.  
  337. /* This function searches through the entire search path for a given tag.
  338.  * If it finds the tag, then it displays the info and returns TRUE;
  339.  * otherwise it returns FALSE.
  340.  */
  341. int find(tag)
  342.     char    *tag;    /* the tag to look up */
  343. {
  344.     char    *tagpath;
  345.     char    dir[80];
  346.     char    *ptr;
  347.     int    len;
  348.  
  349.     if (colons == 1)
  350.     {
  351.         /* looking for static function -- only look in current dir */
  352.         tagpath = ".";
  353.     }
  354.     else
  355.     {
  356.         /* get the tagpath from the environment.  Default to DEFTAGPATH */
  357.         tagpath = getenv("TAGPATH");
  358.         if (!tagpath)
  359.         {
  360.             tagpath = DEFTAGPATH;
  361.         }
  362.     }
  363.  
  364.     /* for each entry in the path... */
  365.     while (*tagpath)
  366.     {
  367.         /* Copy the entry into the dir[] buffer */
  368.         for (ptr = dir; *tagpath && *tagpath != SEP; tagpath++)
  369.         {
  370.             *ptr++ = *tagpath;
  371.         }
  372.         if (*tagpath == SEP)
  373.         {
  374.             tagpath++;
  375.         }
  376.  
  377.         /* if the entry ended with "/tags", then strip that off */
  378.         len = strlen(TAGS);
  379.         if (&dir[len] < ptr && ptr[-len - 1] == SLASH && !strncmp(&ptr[-len], TAGS, len))
  380.         {
  381.             ptr -= len + 1;
  382.         }
  383.  
  384.         /* if the entry is now an empty string, then assume "." */
  385.         if (ptr == dir)
  386.         {
  387.             *ptr++ = '.';
  388.         }
  389.         *ptr = '\0';
  390.  
  391.         /* look for the tag in this path.  If found, then display it
  392.          * and exit.
  393.          */
  394.         ptr = cktagdir(tag, dir);
  395.         if (ptr)
  396.         {
  397.             /* just supposed to display tag info? */
  398.             if (taginfo)
  399.             {
  400.                 /* then do only that! */
  401.                 if (strcmp(dir, "."))
  402.                 {
  403.                     printf("%s%c%s", dir, SLASH, ptr);
  404.                 }
  405.                 else
  406.                 {
  407.                     /* avoid leading "./" if possible */
  408.                     fputs(ptr, stdout);
  409.                 }
  410.                 return 1;
  411.             }
  412.             else
  413.             {
  414.                 /* else look up the declaration of the thing */
  415.                 return lookup(dir, ptr);
  416.             }
  417.         }
  418.     }
  419.  
  420.     /* if we get here, then the tag wasn't found anywhere */
  421.     return 0;
  422. }
  423.  
  424. void usage()
  425. {
  426.     fputs("usage: ref [-t] [-c class] [-f file] tag\n", stderr);
  427.     fputs("   -t        output tag info, instead of the function header\n", stderr);
  428.     fputs("   -f File   tag might be a static function in File\n", stderr);
  429.     fputs("   -c Class  tag might be a member of class Class\n", stderr);
  430.     exit(2);
  431. }
  432.  
  433.  
  434. int countcolons(str)
  435.     char    *str;
  436. {
  437.     while (*str != ':' && *str)
  438.     {
  439.         str++;
  440.     }
  441.     if (str[0] != ':')
  442.     {
  443.         return 0;
  444.     }
  445.     else if (str[1] != ':')
  446.     {
  447.         return 1;
  448.     }
  449.     return 2;
  450. }
  451.  
  452. void main(argc, argv)
  453.     int    argc;
  454.     char    **argv;
  455. {
  456.     char    def_tag[100];    /* used to build tag name with default file/class */
  457.     int    i;
  458.  
  459.     /* parse flags */
  460.     for (i = 1; i < argc && argv[i][0] == '-'; i++)
  461.     {
  462.         switch (argv[i][1])
  463.         {
  464.           case 't':
  465.             taginfo = 1;
  466.             break;
  467.  
  468.           case 'f':
  469.             if (argv[i][2])
  470.             {
  471.                 def_file = &argv[i][2];
  472.             }
  473.             else if (++i < argc)
  474.             {
  475.                 def_file = argv[i];
  476.             }
  477.             else
  478.             {
  479.                 usage();
  480.             }
  481.             break;
  482.  
  483.           case 'c':
  484.             if (argv[i][2])
  485.             {
  486.                 def_class = &argv[i][2];
  487.             }
  488.             else if (++i < argc)
  489.             {
  490.                 def_class = argv[i];
  491.             }
  492.             else
  493.             {
  494.                 usage();
  495.             }
  496.             break;
  497.  
  498.           default:
  499.             usage();
  500.         }
  501.     }
  502.  
  503.     /* if no tag was given, complain */
  504.     if (i + 1 != argc)
  505.     {
  506.         usage();
  507.     }
  508.  
  509.     /* does the tag have an explicit class or file? */
  510.     colons = countcolons(argv[i]);
  511.  
  512.     /* if not, then maybe try some defaults */
  513.     if (colons == 0)
  514.     {
  515.         /* try a static function in the file first */
  516.         if (def_file)
  517.         {
  518.             sprintf(def_tag, "%s:%s", def_file, argv[i]);
  519.             colons = 1;
  520.             if (find(def_tag))
  521.             {
  522.                 exit(0);
  523.             }
  524.         }
  525.  
  526.         /* try a member function for a class */
  527.         if (def_class)
  528.         {
  529.             sprintf(def_tag, "%s::%s", def_class, argv[i]);
  530.             colons = 2;
  531.             if (find(def_tag))
  532.             {
  533.                 exit(0);
  534.             }
  535.         }
  536.  
  537.         /* oh, well */
  538.         colons = 0;
  539.     }
  540.  
  541.     /* find the tag */
  542.     if (find(argv[i]))
  543.     {
  544.         exit(0);
  545.     }
  546.  
  547.     /* Give up.  If doing tag lookup then exit(0), else exit(1) */
  548.     exit(!taginfo);
  549.     /*NOTREACHED*/
  550. }
  551.